#ifndef CUSTOM_DEFERRED_PASS_INCLUDED
#define CUSTOM_DEFERRED_PASS_INCLUDED

#include "../ShaderLib/Surface.hlsl"
#include "../ShaderLib/Shadows.hlsl"
#include "../ShaderLib/Light.hlsl"
#include "../ShaderLib/BRDF.hlsl"
#include "../ShaderLib/GI.hlsl"
#include "../ShaderLib/Lighting.hlsl"
#include "../ShaderLib/GBuffers.hlsl"

float4 _ProjectionParams;

struct Varyings {
	float4 positionCS : SV_POSITION;
	float2 screenUV : VAR_SCREEN_UV;
};

Varyings DefaultPassVertex(uint vertexID : SV_VertexID) {
	Varyings output;
	output.positionCS = float4(
		vertexID <= 1 ? -1.0 : 3.0,
		vertexID == 1 ? 3.0 : -1.0,
		0.0, 1.0);
	output.screenUV = float2(
		vertexID <= 1 ? 0.0 : 2.0,
		vertexID == 1 ? 2.0 : 0.0);
	if (_ProjectionParams.x < 0.0) {
		output.screenUV.y = 1.0 - output.screenUV.y;
	}
	return output;
}

//Display GBuffer Function
float isClip(float2 uv, float2 size) {
	float2 scaledUV = uv * size;
	//Edge Check
	const float edge = 0.02f * size.x;
	float checkEdge1 = (scaledUV.x - edge) * (scaledUV.x - size.x + edge);
	float checkEdge2 = (scaledUV.y - edge) * (scaledUV.y - size.y + edge);
	if (checkEdge1 > 0 || checkEdge2 > 0) return -1;

	//Round Check
	const float radius = 0.1f * size.x;
	const float radius2 = radius * radius;
	float checkRoundEdge1 = (scaledUV.x - radius) * (scaledUV.x - size.x + radius);
	float checkRoundEdge2 = (scaledUV.y - radius) * (scaledUV.y - size.y + radius);
	if (checkRoundEdge1 < 0 || checkRoundEdge2 < 0) return 1; 

	//trick for no overlap
	float2 checkPoint;
	checkPoint = float2(edge + radius, edge + radius); if (dot(checkPoint - scaledUV, checkPoint - scaledUV) < radius2) return 1;
	checkPoint = float2(size.x - edge - radius, edge + radius); if (dot(checkPoint - scaledUV, checkPoint - scaledUV) < radius2) return 1;
	checkPoint = float2(edge + radius, size.y - edge - radius); if (dot(checkPoint - scaledUV, checkPoint - scaledUV) < radius2) return 1;
	checkPoint = float2(size.x - edge - radius, size.y - edge - radius); if (dot(checkPoint - scaledUV, checkPoint - scaledUV) < radius2) return 1;

	return -1;
}

struct FragmentOutput {
	float4 color : COLOR;
#ifdef _DEFERRED_LIGHTING
	float depth : DEPTH;
#endif
};

FragmentOutput DeferrdPassFragment(Varyings input) {
	float2 GBufferSize;
    _GBuffer0.GetDimensions(GBufferSize.x, GBufferSize.y);

	FragmentOutput output;
#ifdef _GET_GBUFFER_ALBEDO
	output.color = float4(GetAlbedo(input.screenUV), 1.0);
	clip(isClip(input.screenUV, GBufferSize));
#elif defined _GET_GBUFFER_DEPTH
	float depth = GetDepth(input.screenUV);
	output.color = float4(depth, depth, depth, 1.0);
    clip(isClip(input.screenUV, GBufferSize));
#elif defined _GET_GBUFFER_NORMAL
	output.color = float4(SAMPLE_TEXTURE2D(_GBuffer1, sampler_GBuffer1, input.screenUV).rgb, 1.0);
    clip(isClip(input.screenUV, GBufferSize));
#elif defined _GET_GBUFFER_LIGHTMAP
	//output.color = float4(GetLightMap(input.screenUV),0.0, 1.0);
	output.color = float4(GetPosition(input.screenUV), 1.0);
    clip(isClip(input.screenUV, GBufferSize));
#elif defined _GET_GBUFFER_ROUGHNESS
	float roughness = SAMPLE_TEXTURE2D(_GBuffer2, sampler_GBuffer2, input.screenUV).b;
	output.color = float4(roughness, roughness, roughness, 1);
	clip(isClip(input.screenUV, GBufferSize));
#else 
	Surface surface;
	surface.color = GetAlbedo(input.screenUV);
	surface.normal = GetNormal(input.screenUV);
	surface.alpha = SAMPLE_TEXTURE2D(_GBuffer0, sampler_GBuffer0, input.screenUV).a;
	surface.metallic = SAMPLE_TEXTURE2D(_GBuffer1, sampler_GBuffer1, input.screenUV).a;
	surface.smoothness = SAMPLE_TEXTURE2D(_GBuffer2, sampler_GBuffer2, input.screenUV).b;
	surface.depth = GetDepth(input.screenUV);
	surface.fresnelStrength = SAMPLE_TEXTURE2D(_GBuffer2, sampler_GBuffer2, input.screenUV).a;
	//calc attribution
	surface.position = GetPosition(input.screenUV);
	surface.viewDirection = normalize(_WorldSpaceCameraPos - surface.position);

#if defined(_PREMULTIPLY_ALPHA)
	BRDF brdf = GetBRDF(surface, true);
#else
	BRDF brdf = GetBRDF(surface);
#endif

	//GI gi = GetGI(GetLightMap(input.screenUV), surface, brdf);
	GI gi;
	gi.shadowMask.always = false;
	gi.shadowMask.distance = false;
#if defined(_SHADOW_MASK_ALWAYS)
	gi.shadowMask.always = true;
#elif defined(_SHADOW_MASK_DISTANCE)
	gi.shadowMask.distance = true;
#endif
	gi.shadowMask.shadows = SAMPLE_TEXTURE2D(_GBuffer4, sampler_GBuffer4, input.screenUV);
	float3 color = GetLighting(surface, brdf, gi);
	color += GetEmission(input.screenUV);

	output.color.rgb = color.rgb;
	//output.color.rgb = surface.position;
	output.color.a = surface.alpha;
	output.depth = GetDepth(input.screenUV);
#endif
	return output;
}
#endif